package core.proto.timeline;

import static app.constants.CollabVizConstants.ANNOTATION_MARGIN;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

import org.apache.commons.io.FilenameUtils;

import core.proto.AllComponents;
import core.proto.Util;
import core.proto.annotation.Annotation;
import core.proto.annotation.AnnotationManager;
import core.proto.annotation.AnnotationRemovalListener;
import core.proto.annotation.CannotAddAnnotationException;
import core.proto.annotation.TimelineAnnotationModel;
import core.proto.annotation.AnnotationModel.AnnotationLocation;
import core.proto.annotation.TimelineAnnotationModel.IntervalRow;
import core.proto.annotation.TimelineAnnotationUI;

import de.jaret.util.date.Interval;
import de.jaret.util.date.JaretDate;
import de.jaret.util.ui.timebars.model.DefaultTimeBarRowModel;
import de.jaret.util.ui.timebars.model.TimeBarRow;
import de.jaret.util.ui.timebars.swing.TimeBarViewer;

/**
 * This extends the TimeBarViewer class provided with the jaret timeline library, and 
 * customizes it. 
 * @author Wei
 */
public class SavantTimeBarViewer extends TimeBarViewer  {

	private static final long serialVersionUID = 1L;
	private SavantIntervalRenderer renderer;	// Draws the intervals on the timeline.   

	private JLayeredPane pane;
	private final SavantTimeBarViewer self;
	private final SavantTimelineModel stm; 

	public SavantTimeBarViewer(JLayeredPane pane, JaretDate start, JaretDate end)  {
		super();
		stm = new SavantTimelineModel(start, end);
		this.setModel(stm);

		this.pane = pane;
		self = this;
		renderer = new SavantIntervalRenderer();
		this.registerTimeBarRenderer(Interval.class, renderer);
		registerMouseAdapter();
		this.setFocusable(true);
	}

	public void externalAddAnnotation (Annotation annotation) {
		TimelineAnnotationModel m = ((TimelineAnnotationModel) annotation.getModel());
		AnnotationInterval interval = new AnnotationInterval(annotation, m.getStart(), m.getEnd(), m.getRow() == IntervalRow.MORNING ? stm.getMorningRow() : stm.getEveningRow());
		interval.row.addInterval(interval);
		((TimelineAnnotationUI) annotation.getView()).setAnnotationInterval(interval);
	}

	/**
	 * Adds the mouse adapter that provides mouse interactivity on the timeline. 
	 */
	private void registerMouseAdapter(){
		final TimeBarViewer tbv = this;

		MouseAdapter adapter = new MouseAdapter(){

			private JaretDate startDate = null;
			//			private AnnotationInterval currentInterval = null;

			public void mousePressed (MouseEvent me) {
				// Remember the location where mouse is pressed.
				List<Interval> intervals = tbv.getDelegate().getIntervalsAt(me.getX(), me.getY());
				if (intervals.size() > 0){
					// Ignore drags over existing intervals. 
					return; 
				}
				// Make sure user dragged mouse over row area only. 
				TimeBarRow row = tbv.getRowForXY(me.getX(), me.getY());
				if (row != null){
					// Remember the start date for mouse release. 
					startDate = tbv.dateForXY(me.getX(), me.getY());
				}
			}

			public void mouseReleased (MouseEvent me) {
				if (startDate != null){					
					TimeBarRow row = tbv.getRowForXY(me.getX(), me.getY());
					if (row != null){
						if (row instanceof DefaultTimeBarRowModel){
							DefaultTimeBarRowModel rowModel = (DefaultTimeBarRowModel) row;
							// Get the ending date. 
							JaretDate endDate = tbv.dateForXY(me.getX(), me.getY());
							if (startDate.compareTo(endDate) > 0){
								startDate = endDate;
								endDate = startDate;
							}

							final int MIN_INTERVAL_LENGTH = 360;							
							if (endDate.diffSeconds(startDate) >= MIN_INTERVAL_LENGTH){
								// Create interval object. 
								String docKey = FilenameUtils.getBaseName(AllComponents.getCurrentPath());

								try {
									TimelineAnnotationModel model = new TimelineAnnotationModel(startDate, endDate, "", docKey, rowModel == stm.getEveningRow() ? IntervalRow.EVENING : IntervalRow.MORNING);
									TimelineAnnotationUI ui;
									ui = new TimelineAnnotationUI(model);
									ui.addToPane(pane);
									ui.show(me.getX(), me.getY());
									AnnotationInterval interval = new AnnotationInterval(new Annotation(model, ui, false), startDate, endDate, rowModel);
									rowModel.addInterval(interval);
								} catch (CannotAddAnnotationException e) {
									Util.showCannotAddAnnotationPopup(self);
								}

							}
						}

					}

				}
				startDate = null;
			}

			/**
			 * If click on interval, show popup to edit text.  
			 */
			public void mouseClicked(MouseEvent me){
				// Single clicks to edit.  
				if (me.getClickCount() == 1){

					List<Interval> intervals = tbv.getDelegate().getIntervalsAt(me.getX(), me.getY());
					requestFocusInWindow();

					// Then check if we clicked on any existing intervals.
					if (intervals.size() > 0){
						Interval interval = intervals.get(0);

						if (interval instanceof AnnotationInterval){
							((AnnotationInterval) interval).getAnnotation().getView().show(me.getX(), me.getY());
						}
					}
					repaint();
				}
			}
		};

		this.addMouseListener(adapter);
	}
}
